<?php
/**
 * dar域对象管理器
 *
 * @package util.dar
 * @version $Id: IDarManager.php 316 2008-05-04 10:50:39Z iwind $
 * @since 0.1
 */
class IDarManager extends IObject {
	/**
	 * 模型
	 *
	 * @var IDarModel
	 */
	private $model;
	
	/**
	 * 驱动
	 *
	 * @var IDarProvider
	 */
	private $provider;
	
	/**
	 * 是否为单例模式
	 *
	 * @var boolean
	 * @since 0.2
	 */
	private static $singleton = false;
	
	/**
	 * 域对象容器
	 *
	 * @var array
	 * @since 0.2
	 */
	private $domains = array("ids" => array(), "conds" => array());
	
	/**
	 * 构造
	 *
	 * @param IDarProvider $provider 驱动
	 * @param IDarModel $model 模型
	 * @since 0.1
	 */
	public function __construct(IDarModel $model) {
		$this->provider = $model->getProvider();
		$this->model = $model;
	}
	
	 /**
     * 执行SQL语句
     *
     * @param string $sql SQL
     * @param array $params 参数
     * @return IDbStatement
     * @since 0.1
     */
    public function exec($sql, array $params = null) {
    	return $this->provider->exec($this->model, $sql, $params);
    }
    
    /**
     * 使用SQL获取域对象
     *
     * @param string $sql SQL语句
     * @param array $params 参数
     * @return IDarDomain
     * @since 0.2
     */
   	public function findBySql($sql, array $params = null) {
   		return $this->provider->findBySql($this->model, $sql, $params);
   	}
	
     /**
     * 使用SQL获取域对象
     *
     * @param string $sql SQL语句
     * @param array $params 参数
     * @return array
     * @since 0.2
     */	
   	public function findAllBySql($sql, array $params = null) {
   		return $this->provider->findAllBySql($this->model, $sql, $params);
   	}
    
    /**
     * 检查是否存在
     * 
     * 使用IDarQuery的例子：
     * <code>
     * $exist = TLog::manager()->exists(IDarQuery::create(array(
     * 		"cond" => "[TLog.arId]=1 AND [TLog.talId]=3"
     * 	)));
     * </code>
     *
     * @param mixed $param 可以为IDarQuery，也可以为ID，还可以为一组ID
     * @return boolean
     * @since 0.1
     */
    public function exists($param) {
    	return $this->provider->exists($this->model, $param);
    }
	
	/**
	 * 根据主键查询记录
	 *
	 * @param mixed $id 主键
	 * @return IDarDomain
	 * @since 0.1
	 */
	public function find($id) {
		if (self::$singleton && array_key_exists($id, $this->domains["ids"])) {
			return $this->domains["ids"][$id];
		}
		$domain = $this->provider->find($this->model, $id);
		$this->addToDomains($domain);
		return $domain;
	}
	
	/**
	 * 查询单条记录
	 *
	 * @param array $query 条件
	 * @return IDarDomain
	 * @since 0.1
	 */
	public function findByQuery(array $query) {
		$queryString = serialize($query);
		if (self::$singleton && array_key_exists($queryString, $this->domains["conds"])) {
			return $this->domains["conds"][$queryString];
		}
		$darQuery = IDarQuery::create($query);
		$darQuery->setSize(1);
		$domain = $this->provider->findByQuery($this->model, $darQuery);
		$this->addToDomains($domain, $queryString);
		return $domain;
	}
	
	/**
	 * 使用字段值查找一行记录
	 *
	 * @param array $array 字段值，如array("field1"=>1, "field2"=>"string");
	 * @return IDarDomain
	 * @since 0.1.1
	 */
	public function findByFields(array $array) {
		$queryString = serialize($array);
		if (self::$singleton && array_key_exists($queryString, $this->domains["conds"])) {
			return $this->domains["conds"][$queryString];
		}
		
		$rows = $this->provider->findAllByFields($this->model, $array);
		$domain = (empty($rows))?null:$rows[0];
		$this->addToDomains($domain, $queryString);
		return $domain;
	}
	
	/**
	 * 根据条件查询所有相关记录
	 *
	 * $query = array(
	 * 		"offset"=>1,
	 * 		"size"=>10,
	 * 		"orders"=>array("Blog", "id"),
	 * 		"condition"=>"[Blog.category]=:categoryId"
	 * 		"parameters"=>array("categoryId"=>1)
	 * );
	 * 
	 * @param array $query 查询条件
	 * @return array
	 * @since 0.1
	 */
	public function findAll(array $query = null) {
		$darQuery = IDarQuery::create($query);
		$array = $this->provider->findAll($this->model, $darQuery);
		return $array;
	}
	
	/**
	 * 使用字段值查找一组记录
	 *
	 * @param array $array 字段值，如array("field1"=>1, "field2"=>"string");
	 * @return array
	 * @since 0.1
	 */
	public function findAllByFields(array $array) {
		return $this->provider->findAllByFields($this->model, $array);
	}
	
	/**
	 * 查找字段值在数组中的记录
	 *
	 * @param string $field 字段名
	 * @param array $array
	 * @return array
	 * @since 0.1
	 */
	public function findAllInArray($field, array $array) {
		return $this->provider->findAllInArray($this->model, $field, $array);
	}
	
	/**
	 * 根据条件计算记录数
	 *
	 * @param array $query 查询条件
	 * @return integer
	 * @since 0.1
	 */
	public function count(array $query = null) {
		$darQuery = IDarQuery::create($query);
		return $this->provider->count($this->model, $darQuery);
	}
	
	/**
	 * 新建
	 *
	 * @param array $properties 属性
	 * @return IDarDomain 域对象
	 * @since 0.1
	 */
	public function create(array $properties = null) {
		$domain = $this->model->createDomain();
		$domain->setDarFieldValues($properties);
		return $domain;
	}
	
	/**
	 * 根据分页做查询
	 *
	 * @param IPager $page 分页
	 * @param array $query 查询
	 * @return IPager
	 * @since 0.1
	 */
	public function queryPage(IPager $page, array $query = null) {
		if ($query == null) {
			$query = array();
		}
		$count = $this->count($query);
		if ($count == 0) {
			return $page;
		}
		$page->setContentSize($count);
		$query["offset"] = $page->getStartOffset();
		$query["size"] = $page->getPageSize();
		$page->addRows($this->findAll($query));
		return $page;
	}
	
	/**
	 * 是否开启单例模式
	 *
	 * 如果开启了单例模式，所有具有同一ID的记录均为同一对象，目前只对IDarManager::find(),IDarManager::findByXxx()方法产生影响。
	 * 
	 * 建议只在只读的情况下，打开单例模式，否则在不同进程或线程同时访问时可能出现数据不同步的现象。
	 * 
	 * @param boolean $singleton 是否为单例模式
	 * @since 0.2
	 */
	public static  function setSingleton($singleton) {
		self::$singleton = $singleton;
	}
	
	/**
	 * 添加到domains容器中
	 *
	 * @param IDarDomain $domain 域对象
	 * @param mixed $cond 条件 
	 * @since 0.2
	 */
	private function addToDomains($domain, $cond = null) {
		if ($domain != null && self::$singleton) {
			$this->domains["ids"][$domain->getIdValue()] = $domain;
			if ($cond != null) {
				$this->domains["conds"][$cond] = $domain;
			}
		}
	}
	
	/**
	 * 删除相关记录并返回影响的行数
	 *
	 * @param array $query 查询
	 * @return integer
	 * @since 0.2
	 */
	public function deleteAll(array $query = null) {
		return $this->provider->deleteAll($this->model, IDarQuery::create($query));
	}
}

?>